import React from "react";
import { Message, Event } from 'grey-message';

/** 数据修改函数 */
export type IMethod<S, Option> = (boxState: S, option?: Option, box?: ControllerBase<S>) => Promise<any>;

/** 控制器基础 */
export class ControllerBase<S> extends Message{

    /** 当前状态 */
    private boxState: S;

    constructor(state: S) {
        super();
        this.boxState = state;
    }

    /** 当前自己盒子 */
    public get state() {
        return this.boxState;
    }

    /** 
     * 绑定数据的钩子(适用于组件开发)
     */
    useMemo: <A = any>(fn: (boxState: S) => A) => A = (factory: (boxState: S) => any) => {

        const [state, setState] = React.useState(factory(this.boxState));

        const runState = React.useCallback(() => { setState(factory(this.boxState)) }, [factory]);

        React.useEffect(() => this.on(StateChangeEvent.TYPE, runState), [runState]);

        React.useEffect(() => { setState(factory(this.boxState)) }, [factory]);

        return state;
    }

    /**
     * 绑定修改数据的方法
     * @param method 绑定的函数
     */
    public action<Option = undefined>(method: IMethod<S, Option>) {
        return async (option?: Option) => {
            const ret = await method(this.boxState, option, this);
            this.send(new StateChangeEvent());
            return ret;
        }
    }

    /** 修改状态的快速通道 */
    public async run(fn: (s: S) => Promise<any>) {
        return await this.action(fn)();
    }
}

/** 状态变化事件 */
export class StateChangeEvent extends Event {
    static TYPE = 'STATE_CHANGE_EVENT';
    constructor() {
        super(StateChangeEvent.TYPE);
    }
}